#region License, Terms and Conditions
//
// Prawks - Copyright (c) 2007 Atif Aziz. All rights reserved.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your option)
// any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
//
#endregion

namespace Prawks.DbMethods
{
    using System;
    
    using Debug = System.Diagnostics.Debug;
    using ParameterInfo = System.Reflection.ParameterInfo;
    using ParameterDirection = System.Data.ParameterDirection;

    /// <summary>
    /// Provides logical reflection information for a parameter on an input
    /// or output (data access) method.
    /// </summary>
    
    [ Serializable ]
    public sealed class DbMethodParameterInfo
    {
        readonly ParameterInfo _inParameter;
        readonly ParameterInfo _outParameter;

        /// <summary>
        /// Initializes a new instance of the <see cref="DbMethodParameterInfo"/> 
        /// class with the input and output parameter information.
        /// </summary>
        /// <param name="inParameter">
        /// The parameter from the input method to be logically represented by 
        /// this instance.
        /// </param>
        /// <param name="outParameter">
        /// The parameter from the output method to be logically represented by 
        /// this instance.
        /// </param>
        
        internal DbMethodParameterInfo(ParameterInfo inParameter, ParameterInfo outParameter)
        {
            Debug.Assert(inParameter != null || outParameter != null);
            
            _inParameter = inParameter;
            _outParameter = outParameter;
        }

        /// <summary>
        /// Gets the input parameter being logically represented.
        /// </summary>

        public ParameterInfo InParameter 
        {
            get { return _inParameter; }
        }

        /// <summary>
        /// Gets the output parameter being logically represented.
        /// </summary>

        public ParameterInfo OutParameter 
        {
            get { return _outParameter; }
        }

        /// <summary>
        /// Gets the name of the parameter.
        /// </summary>

        public string Name
        {
            get { return Logical.Name; }
        }
        
        /// <summary>
        /// Gets the direct (canonical) type of the parameter.
        /// </summary>

        public Type DirectType
        {
            get
            {
                Type type = Logical.ParameterType;
                return type.IsByRef ? type.GetElementType() : type;
            }
        }

        /// <summary>
        /// Gets an instance of the <see cref="DbParameterAttribute"/> attribute
        /// applied to either the input or the output parameter.
        /// </summary>

        public DbParameterAttribute GetDbParameterAttribute()
        {
            return (DbParameterAttribute) Attribute.GetCustomAttribute(Logical, typeof(DbParameterAttribute));
        }

        /// <summary>
        /// Infers the direction for a command parameter depending on the type
        /// and presence of the input and output parameters.
        /// </summary>
        /// <returns>
        /// Returns the inferred direction.
        /// </returns>
        
        public ParameterDirection InferDirection()
        {
            ParameterInfo parameter = _inParameter != null ? 
                _inParameter : _outParameter;

            if (parameter.ParameterType.IsByRef)
            {
                return parameter.IsOut ? 
                    ParameterDirection.Output : 
                    ParameterDirection.InputOutput;
            }

            return _outParameter != null ? 
                ParameterDirection.InputOutput : ParameterDirection.Input;
        }

        private ParameterInfo Logical
        {
            get { return _inParameter == null ? _outParameter : _inParameter; }
        }
    }
}
